#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdlib>
#include <string>
#include <thread>
#include <vector>
#include <stdio.h>
#include <cstring>
#include "LockGuard.hpp"

using namespace std;
#define NUM 4

int tickets = 1000; // 用多线程，模拟一轮抢票
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//全局锁

class threadData
{
public:
    threadData(int number)
        : _threadname("thread-" + to_string(number))
    {}
public:
    string _threadname;
};


void* getTicket(void* args)
{
    threadData* td = static_cast<threadData*>(args);
    const char* name = td->_threadname.c_str(); 
    
    while(true)
    {
        // tickets - 共享资源 - 临界资源
        // 访问临界资源的代码 - 临界区
        pthread_mutex_lock(&lock);//加锁
        pthread_mutex_lock(&lock);//加锁
        // 申请锁成功，才能往后执行，不成功，阻塞等待
        if(tickets > 0) //可以抢票
        {
            usleep(1000); 
            printf("who = %s, get a ticket: %d\n", name, tickets);
            tickets--; //每抢到一张票,总量减一
            pthread_mutex_unlock(&lock);//解锁
        }
        else
        {
            pthread_mutex_unlock(&lock);//解锁
            break;
        }
        usleep(10);  //新加
    }  
    printf("%s ... quit\n", name);
    

    return nullptr;
}

/*
void* getTicket(void* args)
{
    threadData* td = static_cast<threadData*>(args);
    const char* name = td->_threadname.c_str(); 
    
    while(true)
    {
        {
            // tickets - 共享资源 - 临界资源
            // 访问临界资源的代码 - 临界区
            // 申请锁成功，才能往后执行，不成功，阻塞等待
            LockGuard lockguard(&lock); // 临时的LockGuard对象，RAII风格的锁
            if(tickets > 0) //可以抢票
            {
                usleep(1000); 
                printf("who = %s, get a ticket: %d\n", name, tickets);
                tickets--; //每抢到一张票,总量减一
            }
            else
            {
                break;
            }
            // 临时的LockGuard对象除出了作用域就会调用析构函数去释放锁
        }
        usleep(10);  //让这个不要成为临界区
    }  
    printf("%s ... quit\n", name);
    

    return nullptr;
}
*/


int main()
{
    pthread_mutex_t lock; // 锁 - main函数栈上开辟的空间
    pthread_mutex_init(&lock, nullptr);// 初始化锁


    vector<pthread_t> tids;
    vector<threadData*> thread_datas;

    for (int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        // 让每个线程都拿到这把锁
        threadData* td = new threadData(i);//给线程起名字
        thread_datas.push_back(td);

        pthread_create(&tid, nullptr, getTicket, thread_datas[i - 1]);
        tids.push_back(tid);
    }

    for(auto thread: tids)// 等待所有线程
    {
        pthread_join(thread, nullptr);
    }

    for(auto td : thread_datas)
    {
        delete td;
    }
    // 释放锁
    pthread_mutex_destroy(&lock);
    return 0;
}



/*
void* getTicket(void* args)
{
    threadData* td = static_cast<threadData*>(args);
    const char* name = td->_threadname.c_str(); 
    
    while(true)
    {
        // tickets - 共享资源 - 临界资源
        // 访问临界资源的代码 - 临界区
        //pthread_mutex_lock(&lock);//加锁
        // 申请锁成功，才能往后执行，不成功，阻塞等待
        if(tickets > 0) //可以抢票
        {
            usleep(1000); 
            printf("who = %s, get a ticket: %d\n", name, tickets);
            tickets--; //每抢到一张票,总量减一
            //pthread_mutex_unlock(&lock);//解锁
        }
        else
        {
           // pthread_mutex_unlock(&lock);//解锁
            break;
        }
        usleep(10);  //新加
    }  
    printf("%s ... quit\n", name);
    

    return nullptr;
}
*/



//
//#define NUM 4

//pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
//int tickets = 1000; // 用多线程，模拟一轮抢票

//class threadData
//{
//public:
//    threadData(int number, pthread_mutex_t* lock)
//        : _threadname("thread-" + to_string(number))
 //       , _lock(lock)
//    {}
//
//public:
 //   string _threadname;
 //   pthread_mutex_t* _lock;
//};
/*
void* getTicket(void* args)
{
    threadData* td = static_cast<threadData*>(args);
    const char* name = td->_threadname.c_str(); 
    
    while(true)
    {
        // tickets - 共享资源 - 临界资源
        // 访问临界资源的代码 - 临界区
        pthread_mutex_lock(td->_lock);//加锁
        // 申请锁成功，才能往后执行，不成功，阻塞等待
        if(tickets > 0) //可以抢票
        {
            usleep(1000); 
            printf("who = %s, get a ticket: %d\n", name, tickets);
            tickets--; //每抢到一张票,总量减一
            pthread_mutex_unlock(td->_lock);//解锁
        }
        else
        {
            pthread_mutex_unlock(td->_lock);//解锁
            break;
        }
        usleep(10);  //新加
    }  
    printf("%s ... quit\n", name);
    

    return nullptr;
}

int main()
{
    pthread_mutex_t lock; // 锁 - main函数栈上开辟的空间
    pthread_mutex_init(&lock, nullptr);// 初始化锁


    vector<pthread_t> tids;
    vector<threadData*> thread_datas;

    for (int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        // 让每个线程都拿到这把锁
        threadData* td = new threadData(i, &lock);//给线程起名字
        thread_datas.push_back(td);

        pthread_create(&tid, nullptr, getTicket, thread_datas[i - 1]);
        tids.push_back(tid);
    }

    for(auto thread: tids)// 等待所有线程
    {
        pthread_join(thread, nullptr);
    }

    for(auto td : thread_datas)
    {
        delete td;
    }
    // 释放锁
    pthread_mutex_destroy(&lock);
    return 0;
}
*/



/*
#define NUM 3

int* p; //全局

struct ThreadData
{
    ThreadData(string name)
        :_tname(name)
    {}
    string _tname;
};

string toHex(pthread_t tid)
{
    char hex[64];
    snprintf(hex, sizeof(hex), "%p", tid);
    return hex;
}

__thread pthread_t tid = 0;
__thread pid_t id = 0;

void* threadRountine(void* args)
{

    if(tid == 0 && id == 0)
    {
        tid = pthread_self();
        id = getpid();
    }
    pthread_detach(tid);
    int test_i = 0;
    ThreadData* tid = static_cast<ThreadData*>(args);
    int i = 0;

    // 访问线程2的数据
    if(tid->_tname == "thread2")
        p = &test_i;
    while(i < 10)
    {
        cout << "pid: " << getpid()
        << ", tid: " << toHex(pthread_self())
        << ", threadname: " << tid->_tname
        << ", test_i: " << test_i
        << ", &test_i: " << toHex((pthread_t)&test_i) << endl;
        sleep(1);
        i++;
        test_i++;
    }
    delete tid;
    return nullptr;
}

int main()
{
    vector<pthread_t> tids;
    for(int i = 0; i < 3; i++)
    {
        pthread_t tid;
        // 此时指针变量依然会释放，但是堆上开辟的空间不会
        // 证明堆空间是所有线程共享的，只不过我们一个线程一个
        ThreadData* td = new ThreadData("thread" + to_string(i));

        pthread_create(&tid, nullptr, threadRountine, (void*)td);

        tids.push_back(tid);
    }

    sleep(1);// 确定复制成功

    // 对目标线程进行分离
    //for(auto i : tids)
    //{
       // pthread_detach(i);
    //}

    cout << "main thread get a thread-2 local val: " << *p << ", &p: " << p << endl;
    // joinable和分离是冲突的，一个线程不能既是joinable又是分离的。
    for(int i = 0; i < tids.size(); i++)
    {
        int n = pthread_join(tids[i], nullptr);
        printf("n = %d, who = 0x%p, why: %s\n", n, tids[i], strerror(n));
    }
    //主线程一定最后退出
    return 0;
}
*/

/*
string toHex(pthread_t tid)
{
    char hex[64];
    snprintf(hex, sizeof(hex), "%p", tid);
    return hex;
}

void* threadRoutine(void* args)
{
    while(true)
    {
        cout << "thread id: " << toHex(pthread_self()) << endl;
        sleep(1);
    }
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadRoutine, (void*)"new thread");
    cout << "main thread create down, new thread id: " << toHex(tid) << endl;
    pthread_join(tid, nullptr);
    return 0;
}
*/

/*
void threadrun()
{
    while(true)
    {
        cout << "I am a new thread for C++" << endl;
        sleep(1);
    }
}

int main()
{
    thread t1(threadrun);
    t1.join();
    return 0;
}
*/

/*
class Request
{
public:
    Request(int start, int end, const string& threadname)
        :_start(start)
        ,_end(end)
        ,_threadname( threadname)
        {}
public:
    int _start;
    int _end;
    string _threadname;
};

class Respnose
{
public:
    Respnose(int result, int exitcode)
        :_result(result)
        ,_exitcode(exitcode)
        {}

public:
    int _result;//计算结果
    int _exitcode;//计算结果是否可靠
};

void* sumCount(void* args)
{
    Request* rq = static_cast<Request*>(args);
    // Request* rq = (Request*)args;
    Respnose* rsp = new Respnose(0, 0);
    for(int i = rq->_start; i <= rq->_end; i++)
    {
        rsp->_result += i;
    }
    delete rq;
    return rsp;
}

int main()
{
    pthread_t tid;
    Request* rq = new Request(1, 100, "new thread");
    pthread_create(&tid, nullptr, sumCount, (void*)rq);

    void* ret;
    pthread_join(tid, &ret);
    Respnose* rsp = static_cast<Respnose*>(ret);
    cout << "rsp->_result: " << rsp->_result << endl;
    cout << "rsp->_exitcode: " << rsp->_exitcode << endl;

    delete rsp;
    return 0;
}
*/

/*
void show(const string& name)
{
    cout << name << " say: " << "hello thread" << endl;
}

// new thread
void* threadRountine(void* args)
{
    int cnt = 5;
    const char* name = (const char*)args;
    while(cnt--)
    {
        printf("%s, pid: %d\n",name, getpid());
        sleep(1);
    }
    pthread_exit((void*)1);

    //return (void*)1; // 走到这里默认线程退出啦!
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadRountine, (void*)"new thread");

    sleep(2);//保证新线程已经启动
    pthread_cancel(tid);


    void* retval;
    pthread_join(tid, &retval);

    // 主线程最后退出
    cout << "main tthread quit..., retval: " << (long long int)retval << endl;
    return 0;
}*/

/*
while(true)
{
    cout << "main thread pid: " << getpid() << ", main thread tid: " << tid << endl;
    sleep(1);
}
*/
